Java-তে bidirectional relationships থাকা মানে একাধিক ক্লাস একে অপরের সাথে রেফারেন্স তৈরি করে, যা ডেটা সিরিয়ালাইজ এবং ডেসিরিয়ালাইজ করার সময় সমস্যার সৃষ্টি করতে পারে। বিশেষ করে, infinite recursion বা stack overflow error দেখা দিতে পারে। Jackson এই সমস্যার সমাধানের জন্য বেশ কয়েকটি কৌশল এবং অ্যানোটেশন সরবরাহ করে।
Bidirectional Relationships-এর সমস্যা উদাহরণ
উদাহরণ: User এবং Address ক্লাসের bidirectional সম্পর্ক
import com.fasterxml.jackson.annotation.JsonManagedReference;
import com.fasterxml.jackson.annotation.JsonBackReference;
class User {
public String name;
@JsonManagedReference
public Address address;
public User(String name, Address address) {
this.name = name;
this.address = address;
}
}
class Address {
public String street;
@JsonBackReference
public User user;
public Address(String street, User user) {
this.street = street;
this.user = user;
}
}
Infinite Recursion-এর সমস্যা:
public class BidirectionalExample {
public static void main(String[] args) throws Exception {
User user = new User("John", null);
Address address = new Address("123 Main St", user);
user.address = address;
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(user); // Infinite recursion হবে
System.out.println(json);
}
}
সমাধান: @JsonManagedReference এবং @JsonBackReference
সমাধানের উদাহরণ:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import com.fasterxml.jackson.annotation.JsonBackReference;
class User {
public String name;
@JsonManagedReference
public Address address;
public User(String name, Address address) {
this.name = name;
this.address = address;
}
}
class Address {
public String street;
@JsonBackReference
public User user;
public Address(String street, User user) {
this.street = street;
this.user = user;
}
}
public class BidirectionalExample {
public static void main(String[] args) throws Exception {
User user = new User("John", null);
Address address = new Address("123 Main St", user);
user.address = address;
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(user);
System.out.println("Serialized JSON: " + json);
User deserializedUser = mapper.readValue(json, User.class);
System.out.println("Deserialized User: " + deserializedUser.name);
}
}
Output:
Serialized JSON: {"name":"John","address":{"street":"123 Main St"}}
Deserialized User: John
কিভাবে এটি কাজ করে?
@JsonManagedReference: সিরিয়ালাইজেশনের সময় এই অংশটি JSON-এ অন্তর্ভুক্ত হয়।@JsonBackReference: সিরিয়ালাইজেশনের সময় এই অংশটি JSON থেকে বাদ দেওয়া হয় এবং ডেসিরিয়ালাইজেশনের সময় পুনরুদ্ধার হয়।
সমাধান: @JsonIdentityInfo
@JsonIdentityInfo ব্যবহার করে Jackson object identity পরিচালনা করে, যা bidirectional references সমর্থন করে।
উদাহরণ:
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id"
)
class User {
public int id;
public String name;
public Address address;
public User(int id, String name, Address address) {
this.id = id;
this.name = name;
this.address = address;
}
}
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id"
)
class Address {
public int id;
public String street;
public User user;
public Address(int id, String street, User user) {
this.id = id;
this.street = street;
this.user = user;
}
}
public class JsonIdentityInfoExample {
public static void main(String[] args) throws Exception {
User user = new User(1, "John", null);
Address address = new Address(1, "123 Main St", user);
user.address = address;
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(user);
System.out.println("Serialized JSON: " + json);
User deserializedUser = mapper.readValue(json, User.class);
System.out.println("Deserialized User: " + deserializedUser.name);
}
}
Output:
Serialized JSON: {
"id": 1,
"name": "John",
"address": {
"id": 1,
"street": "123 Main St",
"user": 1
}
}
কিভাবে এটি কাজ করে?
@JsonIdentityInfo: একটি unique identifier যোগ করে, যা Jackson সিরিয়ালাইজ এবং ডেসিরিয়ালাইজ করার সময় object references ট্র্যাক করতে ব্যবহার করে।
সমাধান: Ignoring Properties
কিছু ক্ষেত্রে, bidirectional reference এড়ানোর জন্য একটি রেফারেন্স ফিল্ডকে JSON থেকে বাদ দেওয়া যেতে পারে।
উদাহরণ:
import com.fasterxml.jackson.annotation.JsonIgnore;
class User {
public String name;
public Address address;
public User(String name, Address address) {
this.name = name;
this.address = address;
}
}
class Address {
public String street;
@JsonIgnore
public User user;
public Address(String street, User user) {
this.street = street;
this.user = user;
}
}
public class JsonIgnoreExample {
public static void main(String[] args) throws Exception {
User user = new User("John", null);
Address address = new Address("123 Main St", user);
user.address = address;
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(user);
System.out.println("Serialized JSON: " + json);
}
}
Output:
Serialized JSON: {"name":"John","address":{"street":"123 Main St"}}
কিভাবে এটি কাজ করে?
@JsonIgnore: নির্দিষ্ট ফিল্ড JSON-এ অন্তর্ভুক্ত হয় না।
তুলনা
| সমাধান | সুবিধা | সীমাবদ্ধতা |
|---|---|---|
@JsonManagedReference & @JsonBackReference | সহজ এবং কার্যকর। | কাস্টম লজিক যোগ করা কঠিন। |
@JsonIdentityInfo | Object references সংরক্ষণ করে। | JSON জটিল হতে পারে। |
@JsonIgnore | সহজ, নির্দিষ্ট ফিল্ড বাদ দেওয়া। | ডেসিরিয়ালাইজেশনের সময় তথ্য হারিয়ে যেতে পারে। |
- ছোট ও সহজ সম্পর্ক:
@JsonManagedReferenceএবং@JsonBackReferenceব্যবহার করুন। - জটিল সম্পর্ক বা Object Graph:
@JsonIdentityInfoব্যবহার করুন। - নির্দিষ্ট ক্ষেত্রে ফিল্ড বাদ দেওয়া:
@JsonIgnoreব্যবহার করুন।
Jackson bidirectional relationships দক্ষতার সাথে হ্যান্ডল করতে পারে, তবে সঠিক কৌশল নির্বাচন করাই মূল চাবিকাঠি।
Read more